package org.tcdb.biotools;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;

import org.biojava3.alignment.NeedlemanWunsch;
import org.biojava3.alignment.SimpleGapPenalty;
import org.biojava3.alignment.SimpleSubstitutionMatrix;
import org.biojava3.alignment.template.SubstitutionMatrix;
import org.biojava3.core.sequence.ProteinSequence;
import org.biojava3.core.sequence.compound.AminoAcidCompound;
import org.biojava3.core.util.ConcurrencyTools;
import org.tcdb.biotools.util.SequenceRetrieval;

public class ExtendedGlobalAlignment implements IExtendedAlignment {
	private int shuffles;
	private ProteinSequence subject, target;
	private LinkedHashMap<String, ProteinSequence> subjectList, targetList;
	private final String subjectFormat, targetFormat;
	
	public ExtendedGlobalAlignment(int shuffles, String subject, String target) throws Exception {
		if (subject.split("\\.").length > 1 && subject.split("\\.").length < 5) {
			this.subjectList = SequenceRetrieval.getSequencesForTcid(subject);
			subjectFormat = "map";
		} else if (subject.split("\\.").length > 1) {
			this.subject = SequenceRetrieval.getSequenceForTcid(subject);
			subjectFormat = "single";
		} else {
			this.subject = SequenceRetrieval.getSequenceForTcAccession(subject);
			subjectFormat = "single";
		}
		
		if (target.split("\\.").length > 1 && target.split("\\.").length < 5) {
			this.targetList = SequenceRetrieval.getSequencesForTcid(target);
			targetFormat = "map";
		} else if (target.split("\\.").length > 1) {
			this.target = SequenceRetrieval.getSequenceForTcid(target);
			targetFormat = "single";
		} else {
			this.target = SequenceRetrieval.getSequenceForTcAccession(target);
			targetFormat = "single";
		}
		
		this.shuffles = shuffles;
	
	}
	
	public void setShuffles() {
		// TODO Auto-generated method stub
		
	}
	public int getShuffles() {
		// TODO Auto-generated method stub
		return 0;
	}
	public void setSubject(String fasta) {
		// TODO Auto-generated method stub
		
	}
	public void setSubject(ProteinSequence subject) {
		// TODO Auto-generated method stub
		
	}
	public void setSubjectById(String id) {
		
	}
	
	public ProteinSequence getSubject() {
		// TODO Auto-generated method stub
		return null;
	}
	public void setTarget(String fasta) {
		// TODO Auto-generated method stub
		
	}
	public void setTarget(ProteinSequence target) {
		// TODO Auto-generated method stub
		
	}
	public void setTargetById(String id) {
		
	}
	public ProteinSequence getTarget() {
		// TODO Auto-generated method stub
		return null;
	}
	public void setAlignment() {
		// TODO Auto-generated method stub
		
	}
	public void executeComparison() {
		ConcurrencyTools.setThreadPoolCPUsAvailable(0);
		List<ProteinSequence> subjects = new ArrayList<ProteinSequence>();
		Set<String> sKeys = subjectList.keySet();
		for (String key : sKeys) {
			subjects.add(subjectList.get(key));
		}
		
		List<ProteinSequence> targets = new ArrayList<ProteinSequence>();
		Set<String> tKeys = targetList.keySet();
		for (String key : tKeys) {
			targets.add(targetList.get(key));
		}
		
		SubstitutionMatrix<AminoAcidCompound> matrix = new SimpleSubstitutionMatrix<AminoAcidCompound>();
		List<NeedlemanWunsch<ProteinSequence, AminoAcidCompound>> pairs = new ArrayList<NeedlemanWunsch<ProteinSequence, AminoAcidCompound>>(0);
		int count = 0;
		for (int i = 0; i < subjects.size(); i++) {
			for (int j = 0; j < targets.size(); j++) {
				if (!(subjects.get(i).getSequenceAsString().equals(targets.get(j).getSequenceAsString()))) {
					count++;
					System.out.printf("Building alignment %d of %d...\n", count, subjects.size()*targets.size());
					NeedlemanWunsch<ProteinSequence, AminoAcidCompound> nw = new NeedlemanWunsch<ProteinSequence, AminoAcidCompound>(subjects.get(i), targets.get(j), new SimpleGapPenalty(), matrix);
					pairs.add(nw);
				} else {
					System.out.println("Self-comparison skipped...");
				}
			}
			System.out.println();
		}
		
		System.out.println(pairs.size() + " comparisons conducted.");
		LinkedHashMap<Double, NeedlemanWunsch> scores = new LinkedHashMap<Double, NeedlemanWunsch>();
		if (pairs.size() != 0) {
			System.out.printf("Computing scores....\n");
			for (int i = 0; i<pairs.size(); i++) {
				scores.put(pairs.get(i).getSimilarity(100), pairs.get(i));
			}
		}
		Set<Double> scoreSet = scores.keySet();
		List<Double> scoreList = new ArrayList<Double>();
		for (Double score : scoreSet) {
			scoreList.add(score);
		}
		Collections.sort(scoreList, Collections.reverseOrder());
		for (Double score : scoreList) {
			System.out.printf("Similarity (from 0 to 100) between %s: %f\n", scores.get(score), score);
		}
		ConcurrencyTools.shutdown();	
	}


}
